# @FileName  : ssh.py
# @Time      : 2025/3/23 16:50
# @Author    : LuZhaoHui
# @Software  : PyCharm
# 远程
import os.path
import time
import paramiko
import json
from PIL import Image
from io import BytesIO

from tool.file import *

from PyQt5.QtGui import QImage


def trimList(list):
    index = [i for i, x in enumerate(list) if x == '' or x == ' ']
    for i in index[::-1]:
        del list[i]
    return list


class sshClient(QObject):
    update_item = pyqtSignal(bool)

    def __init__(self, ip, port, user, password, path, timeout=3, timedelay=0.2, loopnums=3):
        super().__init__()

        self.ssh = paramiko.SSHClient()
        self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        self.status = -1
        self.ip = ip
        self.port = port
        self.user = user
        self.password = password
        self.path = path
        self.timeout = timeout
        self.timedelay = timedelay
        self.loopnums = loopnums

    def __del__(self):
        self.ssh.close()

    def sshConnect(self):
        if self.status == 0:
            return self.status
        n = 0
        while True:
            try:
                self.ssh.connect(self.ip, self.port, self.user, self.password, timeout=self.timeout)
                self.status = 0
                save_log('open sshConnect')
                break
            except Exception as e:
                self.status = -1
                self.sshClose()
                err = 'open sshConnect[%s:%s] 失败 %d' % (self.ip, e, n)
                save_log(err)
                print(err)
                if n >= self.loopnums:
                    break
            time.sleep(self.timedelay)
            n += 1
        self.update_item.emit(self.status == 0)
        return self.status

    def sshClose(self, log=True):
        if log:
            save_log('sshClose[%d]' % self.status)
        if self.status == 0:
            self.ssh.close()
        self.update_item.emit(self.status == 0)
        self.status = -1

    def sshSftpOpen(self):
        return self.ssh.open_sftp()

    def sshSftpClose(self, sftp):
        return sftp.close()

    def getCmd(self, cmd):
        list = []
        if self.sshConnect() == 0:
            stdin, stdout, stderr = self.ssh.exec_command(cmd)
            res, err = stdout.read(), stderr.read()
            result = res if res else err
            str = result.decode()
            list = str.split('\n')
            list = trimList(list)
            self.sshClose()
        return list

    def isDir(self, path):
        try:
            cmd = "tree -Ld 1 %s" % path
            ret = self.getCmd(cmd)
            if 'error' in ret[0]:
                return False
            return True
        except:
            self.sshClose()
            return False

    def getDir(self, path, dirDeep=1, isNest=False, isFull=False):
        if isNest:
            cmd = "tree -ifd %s" % path
        else:
            cmd = "tree -ifdL %d %s" % (dirDeep, path)
        try:
            ret = self.getCmd(cmd)
            if 'error' in ret[0]:
                return None
        except:
            self.sshClose()
            return None
        #
        dirs = []
        for line in ret:
            if path == line:
                continue
            if 'directories' in line:
                continue
            if isFull:
                dirs.append(line)
            else:
                dirs.append(line[len(path) + 1:])
        return dirs

    def createDir(self, dir_name):
        cmd = 'mkdir -p "' + dir_name + '"'
        self.getCmd(cmd)

    def removeFile(self, file_name):
        cmd = 'rm -f "' + file_name + '"'
        self.getCmd(cmd)

    def renameFileAB(self, file_name):
        # MV
        dir = os.path.dirname(file_name)
        bname = os.path.basename(file_name).split('.')[0]
        bext = os.path.basename(file_name).split('.')[1]
        if bname[-1] != 'A':
            return
        fileA = file_name
        fileB = dir + '/' + bname[:-1] + 'B.' + bext
        fileC = dir + '/' + bname[:-1] + 'C.' + bext
        # A->C
        cmd = 'mv ' + fileA + ' ' + fileC
        self.getCmd(cmd)
        # B->A
        cmd = 'mv ' + fileB + ' ' + fileA
        self.getCmd(cmd)
        # C->B
        cmd = 'mv ' + fileC + ' ' + fileB
        self.getCmd(cmd)

    def getDirFile(self, path, isNest=False, isFull=False):
        if isNest:
            cmd = "tree -if %s" % path
        else:
            cmd = "tree -ifL 1 %s" % path
        try:
            ret = self.getCmd(cmd)
            if 'error' in ret[0]:
                return None
        except:
            self.sshClose(False)
            return None
        dirs = []
        for line in ret:
            if path == line:
                continue
            if 'directories' in line:
                continue
            if isFull:
                dirs.append(line)
            else:
                dirs.append(line[len(path) + 1:])
        return dirs

    def getFileByte(self, file):
        cmd = "stat --format='%s' " + file
        try:
            ret = self.getCmd(cmd)
            return int(ret[0])
        except:
            self.sshClose(False)
            return 0

    def readFile(self, image_file):
        binary_data = None
        info = []
        if self.sshConnect() == 0:
            try:
                sftp = self.ssh.open_sftp()
                # 打开文件，使用'rb'模式读取二进制文件
                with sftp.open(image_file, 'rb') as file:
                    # 读取整个文件内容到内存中
                    binary_data = file.read()
                    info = getImageInfo(Image.open(BytesIO(binary_data)))
                # 关闭SFTP连接
                sftp.close()
            except:
                self.sshClose()
        return binary_data, info

    def writeFile(self, image_file, binary_data):
        byte = 0
        if self.sshConnect() == 0:
            try:
                sftp = self.ssh.open_sftp()
                with sftp.open(image_file, 'wb') as file:
                    byte = file.write(binary_data)
                sftp.close()
            except:
                self.sshClose()
        return byte

    def getImage(self, image_file):
        image = None
        if self.sshConnect() == 0:
            try:
                sftp = self.ssh.open_sftp()
                # 打开文件，使用'rb'模式读取二进制文件
                with sftp.open(image_file, 'rb') as file:
                    # 读取整个文件内容到内存中
                    binary_data = file.read()
                    image = Image.open(BytesIO(binary_data))
                # 关闭SFTP连接
                sftp.close()
            except:
                self.sshClose()
        return image

    def read_json(self, json_file):
        ret = None
        if self.sshConnect() == 0:
            try:
                sftp = self.ssh.open_sftp()
                # 打开文件，使用'rb'模式读取二进制文件
                with sftp.open(json_file, 'r') as file:
                    json_str = file.read()
                # 关闭SFTP连接
                sftp.close()
                ret = json.loads(json_str)
            except Exception as e:
                self.sshClose()
                err = 'read_json[%s:%s] 失败' % (json_file, e)
                save_log(err)
        return ret

    def save_json(self, save_dict, json_file, mode='w'):
        if self.sshConnect() == 0:
            try:
                sftp = self.ssh.open_sftp()
                # 读取二进制文件
                with sftp.open(json_file, mode) as file:
                    json_str = json.dumps(save_dict, ensure_ascii=False)
                    file.write(json_str)
                # 关闭SFTP连接
                sftp.close()
            except Exception as e:
                self.sshClose()
                err = 'save_json[%s:%s] 失败' % (json_file, e)
                save_log(err)
